using System;
using System.Collections.Generic;
using System.Text;
using CrudI.Interface;

namespace CrudCreator
{
    public class BOCreator
    {

         private List<string> memberNames;
        private List<string> propertiesList;
        private StringBuilder sbTheClassText = new StringBuilder();
        private string memberPrefix = "_";

        private BOCreator(string tableName, string nameSpace)
        {            
            memberNames = new List<string>();
            
            memberNames.Add(Environment.NewLine + "\t\t#region members" + Environment.NewLine + Environment.NewLine);
            propertiesList = new List<string>();
            propertiesList.Add(Environment.NewLine + "\t\t#region properties" + Environment.NewLine + Environment.NewLine);
            CreateClassBegining(tableName, nameSpace);
        }

        private void CreateClassBegining(string tableName, string nameSpace)
        {
            string lineBreak = new string('*', 20);

            if (string.IsNullOrEmpty(nameSpace))
                nameSpace = "<PutNamespaceHere>";

            string classUsing = "using System;" + Environment.NewLine +
                "using System.Collections.Generic;" + Environment.NewLine +
                "using System.Text;" + Environment.NewLine;
          

            sbTheClassText.AppendLine(classUsing);
            
            sbTheClassText.AppendLine(" /* " + lineBreak + " Class created from table " +  tableName +
              " by ~ ASM Code Generator ~ " + lineBreak + " */" + Environment.NewLine);       
                 
            sbTheClassText.AppendLine("namespace " + nameSpace);
            sbTheClassText.AppendLine("{");
            sbTheClassText.AppendLine("\tpublic class " + tableName);
            sbTheClassText.Append("\t{");
        }

        private void AddPropertyAndMembersToLists(IColumn column)
        {
            string comment = "\t\t// Data Type: " + column.DataType;
           
            string propName = column.ColumnName;
            string fieldName = memberPrefix + ConvertFirstLetterToLower(column.ColumnName);
            //propName += column.ColumnName.Substring(1, column.ColumnName.Length -1);
            AddMemberVar( fieldName, column.DataType);
            string property = comment + Environment.NewLine +
                "\t\tpublic " + column.DataType + " " + propName + Environment.NewLine +
                "\t\t{" + Environment.NewLine +
                "\t\t\tget { return " + fieldName + " ; }" + Environment.NewLine +
                "\t\t\tset { " + fieldName + " = value; }" + Environment.NewLine +
                "\t\t}" + Environment.NewLine;

            propertiesList.Add(property + Environment.NewLine);
        }

        private void AddMemberVar(string memberName, string type)
        {
            memberNames.Add("\t\tprivate " + type + " " + memberName + ";" + Environment.NewLine);            
        }

        /// <summary>
        /// Gets the csharp business object for the MySQL table.
        /// </summary>
        /// <param name="table">The table.</param>
        /// <param name="nameSpace">The name space.</param>
        /// <returns>The Business object for a given class</returns>
        public static string GetCsharpBusinessObject(ITable table, string nameSpace)
        {
            BOCreator aClass = new BOCreator(table.TableName, nameSpace);
            foreach (IColumn column in table.ColumnList)
            {
                aClass.AddPropertyAndMembersToLists(column);   
            }

            aClass.propertiesList.Add(Environment.NewLine + "\t\t#endregion properties" + Environment.NewLine);
            aClass.memberNames.Add(Environment.NewLine + "\t\t#endregion members" + Environment.NewLine);
            
            foreach (string s in aClass.propertiesList)
            {
                aClass.sbTheClassText.Append(s);
            }

            foreach (string s in aClass.memberNames)
            {
                aClass.sbTheClassText.Append(s);
            }
            aClass.sbTheClassText.Append(aClass.AddConstructor(table));
            aClass.sbTheClassText.Append(aClass.AddSaveMethod(table));

            // TODO: Add an Insert and an Update Method in CSharpBO
            // the call to these static methods that have already been written
            // in the "AddSaveMethod(table)"

            aClass.sbTheClassText.Append(aClass.AddClassEnd());
            string classAsString = aClass.sbTheClassText.ToString();
            return classAsString;
        }

        private string AddSaveMethod(ITable table)
        {
            StringBuilder sbSaveMethod = new StringBuilder();
            string className = table.TableName;
            sbSaveMethod.Append(Environment.NewLine + "\t\tpublic static bool Save(");
            sbSaveMethod.AppendLine(className + " " + table.TableName.ToLower() + ")");
            sbSaveMethod.AppendLine("\t\t{");

            // if the table has a PK then put the calls to Update and Insert methods in
            if (table.HasPrimaryKey)
            {
                sbSaveMethod.AppendLine("\t\t\tif(" + table.PkField + " > 0)");
                sbSaveMethod.AppendLine("\t\t\t\tUpdate" + className + "(" + table.TableName.ToLower() + ");");
                sbSaveMethod.AppendLine("\t\t\telse");
                sbSaveMethod.AppendLine("\t\t\t\tInsert" + className + "(" + table.TableName.ToLower() + ");");
            }
            else
            {
                sbSaveMethod.AppendLine("\t\t\t// No PK Found on table " + table.TableName + "Unable to write method correctly");
                sbSaveMethod.AppendLine("\t\t\t throw new NotImplementedException(\"This method has not been implemented\");");
            }
            sbSaveMethod.AppendLine("\t\t}");

            return sbSaveMethod.ToString();
        }

        private string AddConstructor(ITable table)
        {
            List<IColumn> fieldList = table.ColumnList;
            string constructorBegining = Environment.NewLine + "\t\tpublic " + table.TableName + "()" + Environment.NewLine +
                "\t\t{" + Environment.NewLine;
            StringBuilder constuctorMiddle = new StringBuilder();
            for (int fieldCounter = 0; fieldCounter < fieldList.Count; fieldCounter++)
            {
                constuctorMiddle.AppendLine("\t\t\t" + GetInitializedVariable(fieldList[fieldCounter])); 
            }
            constuctorMiddle.Append(Environment.NewLine);
            string constuctorEnd = "\t\t}" + Environment.NewLine;
            string fullConstuctor = constructorBegining + constuctorMiddle.ToString() + constuctorEnd;
            return fullConstuctor;
        }

        private string GetInitializedVariable(IColumn mySqlColumn)
        {
            string colName = memberPrefix + ConvertFirstLetterToLower(mySqlColumn.ColumnName);
            string dataType = mySqlColumn.DataType;
            string initializer;
            if (dataType == "string")
                initializer = colName + " = string.Empty;";
            else if (dataType == "int")
                initializer = colName + " = -1;";
            else if (dataType == "bool")
                initializer = colName + " = false;";
            else if (dataType == "decimal")
                initializer = colName + " = -1m;";
            else if (dataType == "DateTime")
                initializer = colName + " = DateTime.Now;";
            else if (dataType == "double")
                initializer = colName + " = -1;";
            else initializer = colName + " = string.Empty;";
            return initializer;
        }
        private string ConvertFirstLetterToLower(string word)
        {
            char firstChar = word[0];
            string newWord = new string(firstChar, 1);
            newWord = newWord.ToLower();
            newWord += word.Substring(1, word.Length - 1);
            return newWord;
        }

        private string AddClassEnd()
        {
            string end = "\t}" + Environment.NewLine + "}";
            return end;
        }
    }
}
